use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use redis::Client;
use sea_orm::{Database, DatabaseConnection};

pub use entity::*;

mod entity;

// 在 Rust 中，尤其是在构建 Web 服务或网络服务时，AppState 结构体经常被用作一个容器，用来存储和管理应用的全局状态或资源。
// 这些资源或状态可以是数据库连接、缓存实例、配置选项、身份验证信息、日志记录器或其他在整个应用中共享或频繁使用的对象。
#[derive(Clone)]
pub struct AppState {
    pub mysql: DatabaseConnection,
    pub redis: Client,
    // pub config: AppConfig,
}
// AppState 共享数据使用参考 axum 官方示例： https://docs.rs/axum/latest/axum/#sharing-state-with-handlers
// AppState实现数据共享 sea-orm 参考： https://github.com/SeaQL/sea-orm/blob/master/examples/axum_example/api/src/lib.rs
/*
如果可能的话，你应该更喜欢使用State，因为它更安全。缺点是它的动态性不如请求扩展。

# Request extensions
这种方法的缺点是，如果你尝试提取一个不存在的扩展，你会得到运行时错误（特别是500内部服务器错误响应），这可能是因为你忘了添加中间件，或者因为你提取了错误的类型。
*/




// 关于 Arc 和 Mutex 的使用，可以参考： https://rustwiki.org/zh-CN/book/ch16-00-concurrency.html
// Mutex 是一个互斥器，它允许一个线程获取互斥器的锁，以独占的方式访问数据。相当于 Java 中的 synchronized 关键字。
// Arc 是一个原子引用计数智能指针，它可以让多个线程同时拥有相同的指针，并共享数据。相当于 Java 中的 volatile 关键字。
// 但是，在一些特殊情况下，比如需要在多个线程之间共享数据，但是又不想使用 Mutex，这时就可以使用 RwLock。
// RwLock 允许多个线程同时读取数据，但是只允许一个线程对数据进行写入。
// 所以，在 Rust 中，一般情况下，我们应该尽量使用 Arc<Mutex<T>>  或者 Arc<RwLock<T>> 来共享数据。
#[derive(Clone, Debug)]
pub struct SharedState {
    // 关于 Arc 和 Mutex 的使用，可以参考： https://rustwiki.org/zh-CN/book/ch16-00-concurrency.html
    // Mutex 是一个互斥器，它允许一个线程获取互斥器的锁，以独占的方式访问数据。相当于 Java 中的 synchronized 关键字，
    // 读写独占的。即使线程只是在读取数据而不是修改数据，仍然必须获得锁才能访问该数据
    pub db_pool: Arc<Mutex<Database>>,
    // RwLock 是读写锁，允许多个线程同时读取数据，但只允许一个线程写入数据。
    pub mysql: Arc<RwLock<DatabaseConnection>>,
    pub redis: Arc<Client>,
    // pub config: AppConfig,
}
// 原子性类型工作起来类似原始类型，不过可以安全的在线程间共享。
// 线程安全带有性能惩罚，我们希望只在必要时才为此买单。如果只是在单线程中对值进行操作，原子性提供的保证并无必要，不使用 Arc 代码反而可以因此运行的更快
/*
在 Rust 中，Arc（原子引用计数）是一种线程安全的引用计数智能指针。它允许你在多个线程间共享所有权，并且当最后一个引用被删除后，会自动清理内存。
这对于需要在不同线程间共享不可变或者可变数据的场景非常有用。
作用：
    线程安全：Arc 能够在线程间安全地共享数据。
    引用计数：Arc 维护一个原子的引用计数，这样可以在多个线程中克隆共享数据的所有权，并且当所有引用都被丢弃时，数据会被释放。
    不可变性或可变性：Arc 可以包含不可变数据 (Arc<T>) 或者与 Mutex 结合使用来包含可变数据 (Arc<Mutex<T>>)。
使用示例：
    let data = Arc::new(42); // 创建一个新的 Arc<T>
    let clone = Arc::clone(&data); // 克隆 Arc<T>
    println!("data: {}, clone: {}", *data, *clone); // 打印数据
与 Mutex<T> 结合使用：
如果你需要共享可变数据，可以将 Arc 与 Mutex 结合使用，以确保数据的线程安全：
fn main() {
    let data = Arc::new(Mutex::new(0)); // 创建一个新的 Arc<Mutex<T>>
    let mut handles = vec![];
    for _ in 0..10 {
        let data = Arc::clone(&data); // 克隆 Arc<Mutex<T>>
        let handle = std::thread::spawn(move || {
            // 锁定数据并修改
            let mut value = data.lock().unwrap();
            *value += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("final value: {}", *data.lock().unwrap());
}
注意事项：
1、Arc 适用于不可变的数据或通过锁机制保护的可变数据。如果你的数据不需要跨线程共享，使用普通的引用或所有权转移可能会更简单、更高效。
2、当使用 Arc 和 Mutex 时，要小心死锁。确保锁的获取和释放顺序一致，不要在一个已经持有的锁上递归获取。
3、Arc 和 Mutex 都有性能惩罚。在单线程中使用原子性类型通常会更快，因为它不需要锁的获取和释放。
4、Arc 和 Mutex 不能被 Send 到其他线程，所以不能在线程间共享。如果需要在线程间共享数据，可以使用其他方法，比如通过消息传递或共享内存。
5、当你使用 Mutex 时，一旦你调用了 .lock() 方法并获得了锁，这个锁会在作用域结束时自动释放。无需担心忘记释放锁导致死锁，因为 Rust 会自动处理。
*/


fn shared_state_demo() {
    // 创建多线程共享数据
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        // 克隆 Arc 指针
        let counter = Arc::clone(&counter);
        // 创建线程
        let handle = thread::spawn(move || {
            //
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}